/**
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Request = require('./requests.js').Request;
var BatchRequest = require('./requests.js').BatchRequest;

/**
 * Constructs a new client with given API name and version.
 * @constructor
 *
 * @param {object} apiMeta Schema returned by Discovery API.
 */
function Client(apiMeta) {
  this.apiMeta = apiMeta;
  this.authClient = null;
  this.defaultParams = null;
  // generate helper methods
  this.extend_(this, apiMeta.resources || {});
}

/**
 * Gets the API's name.
 * @return {String}
 */
Client.prototype.getName = function() {
  return this.apiMeta.name;
};

/**
 * Gets the API's version.
 * @return {String}
 */
Client.prototype.getVersion = function() {
  return this.apiMeta.version;
};

/**
 * @private
 * Extends the object with the given resource and its methods
 * recursively.
 * @param {?object} root Object to be extended.
 */
Client.prototype.extend_ = function(root, resources) {
  for (var key in resources || {}) {
    root[key] = root[key] || {};
    for (var methodName in resources[key].methods || {}) {
      root[key][methodName] =
          this.generateHelper_(resources[key].methods[methodName]);
    }
    this.extend_(root[key], resources[key].resources || {});
  }
};

/**
 * @private
 * Generate a request builder helper.
 *
 * @param {object} methodMeta Method's schema returned by Discovery API.
 * @return {Function} Function generated by methodMeta.
 */
Client.prototype.generateHelper_ = function(methodMeta) {
  var that = this;
  // generates a function to make a request
  // to the resource on given method
  return function(params, body) {
    return that.newRequest(methodMeta, params, body);
  };
};

/**
 * Constructs a request to method with given parameters.
 *
 * @param {string} methodName Full name of the method.
 * @param {?object} params Parameters.
 * @param {object=} opt_resource Optional resource.
 *
 * @return {Request} New Request object constructed with given args.
 */
Client.prototype.newRequest = function(methodMetada, params, opt_resource) {

  return new Request(this.apiMeta, methodMetada, params, opt_resource,
                     this.defaultParams).withAuthClient(this.authClient);
};

/**
 * Adds global auth client.
 *
 * @param {auth.AuthClient} client An auth client instance.
 *
 * @return {Client} Returns itself.
 */
Client.prototype.withAuthClient = function(client) {
  this.authClient = client;
  return this;
};

/**
 * Add default params.
 *
 * @param {object} params Default parameters for all methods.
 *
 * @return {Client} Returns itself.
 */
Client.prototype.withDefaultParams = function(params) {
  this.defaultParams = params;
  return this;
};

/**
 * Exporting Client.
 */
module.exports = Client;
